# encoding: utf-8
import re
import subprocess

import os
import threading

import time

import shutil
import zipfile

import requests
from uiautomator import Device


# 用于App信息存储
class App:
    def __init__(self, name, info, pkg, apk_path=None, act=None, limit_time=100):
        self.name = name
        self.info = info
        self.pkg = pkg
        self.apk_path = apk_path
        self.act = act
        self.limit_time = limit_time

    @classmethod
    def get_demo_apps(cls):
        apps = []
        apps.append(App('DatabaseFill', u'数据库', 'com.meitutest.databasefill', '../apks/databasefill-debug.apk',
                        'com.meitutest.databasefill/.MainActivity'))
        apps.append(App('HelloWorld', u'HelloWorld', 'com.meitutest.helloworld', '../apks/helloworld-debug.apk',
                        'com.meitutest.helloworld/.MainActivity'))
        apps.append(App('Views', u'Views', 'com.meitutest.inflatemoreview', '../apks/inflatemoreview-debug.apk',
                        'com.meitutest.inflatemoreview/.MainActivity'))
        apps.append(App('Bitmap', u'Bitmap', 'com.meitutest.bitmap', '../apks/bitmap-debug.apk',
                        'com.meitutest.bitmap/.ImageViewActivity'))
        return apps

    @classmethod
    def get_sys_apps(cls):
        sys = []
        sys.append(App(u'应用商店', u'应用商店', 'com.android.meitu.appstore', apk_path=None,
                       act='com.android.meitu.appstore/.activity.MeituAppStoreActivity'))
        # sys.append(App('拨号', '拨号', 'com.android.dialer', apk_path=None,
        #                act='com.android.dialer/com.meitu.mobile.contacts.dialer.activities.MeiosDialtactsActivity'))
        # sys.append(App('联系人', '联系人', 'com.android.contacts', apk_path=None,
        #                act='com.android.contacts/.activities.PeopleActivity'))
        sys.append(App(u'信息', u'信息', 'com.android.mms', apk_path=None, act='com.android.mms/.ui.ConversationList'))
        sys.append(App(u'图库', u'图库', 'com.mlab.photos', apk_path=None, act='com.mlab.photos/.app.Photos'))
        sys.append(
            App(u'浏览器', u'浏览器', 'com.android.browser', apk_path=None, act='com.android.browser/.BrowserActivity'))
        sys.append(
            App(u'相机', u'相机-拍照页面', 'com.mlab.cam', apk_path=None, act='com.mlab.cam/com.android.camera.CameraLauncher'))
        sys.append(App(u'时钟', u'时钟', 'com.android.deskclock', apk_path=None,
                       act='com.android.deskclock/com.meitu.mobile.deskclock.MeituDeskClock'))
        sys.append(
            App(u'日历', u'日历', 'com.android.calendar', apk_path=None, act='com.android.calendar/.AllInOneActivity'))
        sys.append(App(u'设置', u'设置', 'com.android.settings', apk_path=None, act='com.android.settings/.Settings'))

        return sys

    @classmethod
    def get_script_app(cls):
        apps = []
        apps.append(App('ScriptApp', u'脚本app', 'com.meitutest.autoscript', '../apks/autoscript-debug.apk'))
        apps.append(
            App('ScriptTest', u'脚本', 'com.meitutest.autoscript.test',
                '../apks/autoscript-debug-androidTest.apk'))
        return apps

    @classmethod
    def get_uiautomator_apk(cls):
        apps = []
        apps.append(App('UiautomatorApk', u'UiAuto app', 'com.github.uiautomator',
                        '../apks/app-uiautomator.apk'))
        apps.append(
            App('UiautomatorTest', u'UiAuto', 'com.github.uiautomator.test',
                '../apks/app-uiautomator-test.apk'))
        return apps

    @classmethod
    def get_listview_demo_apk(cls):
        apps = []
        apps.append(App('ListView', u'ListView', 'com.meitutest.listview',
                        '../listview-debug.apk'))
        return apps

    @classmethod
    def get_pkg_by_app_name(cls, app_name):
        apps = App.get_demo_apps()
        apps.extend(App.get_sys_apps())
        for app in apps:
            print app.info, app_name, app.pkg
            if app.info == app_name:
                return app.pkg
        return None


class ScriptPy:
    def __init__(self, mdev):
        assert isinstance(mdev, MyDevice)
        # windows下的准备
        ui_apps = App.get_uiautomator_apk()
        mdev.install_apk(ui_apps[0])
        mdev.install_apk(ui_apps[1])
        os.system('adb -s ' + mdev.dev_num + ' forward tcp:9008 tcp:9008')

        self.mdev = mdev
        self.dev_num = mdev.dev_num
        self.uiauto_dev = Device(mdev.dev_num)
        self.w = self.uiauto_dev.displayWidth
        self.h = self.uiauto_dev.displayHeight
        self.uiauto_dev.watcher("Dialog").when(textMatches='Agree|同意').click(textMatches='Agree|同意')

    def to_developer(self):
        self.wake_screen_up()
        dev = self.uiauto_dev
        dev.press.home()
        dev.press.home()
        dev.press.home()
        dev(textMatches="拨号|Dialer").click()
        time.sleep(1)
        ok = dev(textMatches="同意|Ok")
        if ok.exists:
            ok.click()
        dev(text="*").click()
        dev(text="#").click()
        dev(text="6").click()
        dev(text="3").click()
        dev(text="4").click()
        dev(text="8").click()
        dev(text="8").click()
        dev(text="#").click()
        time.sleep(1)
        dev(text="开发者选项").click()

    def exit(self):
        self.uiauto_dev.press.back()
        self.uiauto_dev.press.back()
        self.uiauto_dev.press.back()
        self.uiauto_dev.press.back()

    def screen_always_on(self):
        try:
            self.wake_screen_up()
            dev = self.uiauto_dev
            self.to_developer()
            time.sleep(1)
            if dev(textMatches='关闭|Off', enabled=True, clickable=True).exists:
                dev(textMatches='关闭|Off').right(resourceId='com.android.settings:id/switch_widget').click()
                time.sleep(1)
                dev(textMatches='确定|OK').click()
            swicher1 = dev(textMatches='不锁定屏幕|Stay awake').right(resourceId='android:id/switch_widget')
            if not swicher1.checked:
                swicher1.click()
        except Exception, e:
            self.mdev.i('设置常亮出错！' + e.message)

    def connect_wifi(self, ssid, pwd):

        try:
            self.wake_screen_up()
            dev = self.uiauto_dev
            self.go_setting('WLAN|Wi‑Fi')
            time.sleep(1)
            swicher = dev(resourceId='android:id/switch_widget')
            if not swicher.checked:
                swicher.click()
                time.sleep(1)
            isconnect = dev(text=ssid).sibling(textMatches='已连接|Connected').exists
            if isconnect:
                self.exit()
                return isconnect

            ssid = dev(text=ssid)
            while not ssid.exists:
                self.swipe_from_bottom(100)
                time.sleep(0.5)
            ssid.click()
            time.sleep(1)
            dev(resourceId='com.android.settings:id/password').set_text(pwd)
            time.sleep(1)
            dev(textMatches='连接|Connect').click()
            time.sleep(9)
            self.swipe_from_top()
            time.sleep(1)
        except Exception, e:
            self.mdev.i('连接wifi出错！ssid+' + ssid + ' ' + e.message)

    def open_bluetooth(self):
        try:
            self.wake_screen_up()
            self.go_setting('蓝牙|Bluetooth')
            dev = self.uiauto_dev
            swicher = dev(resourceId='android:id/switch_widget')
            if not swicher.checked:
                swicher.click()
        except Exception, e:
            self.mdev.i('设置蓝牙出错！' + e.message)

    def open_gps(self):
        try:
            self.wake_screen_up()
            self.go_setting('通用|General')
            time.sleep(1)
            dev = self.uiauto_dev
            dev(textMatches='定位服务|Location service').click()
            time.sleep(1)
            swicher = dev(resourceId='android:id/switch_widget', instance=0)
            if not swicher.checked:
                swicher.click()
            swicher_1 = dev(resourceId='android:id/switch_widget', instance=1)
            if not swicher_1.checked:
                swicher_1.click()
        except Exception, e:
            self.mdev.i('设置GPS出错！' + e.message)

    def non_screen_lock(self):
        try:
            self.wake_screen_up()
            self.go_setting('指纹与密码|Fingerprint and Password')
            time.sleep(1)
            self.swipe_from_bottom()
            self.uiauto_dev(textMatches='锁屏密码|Lock Screen Password').click()
            time.sleep(1)
            swicher = self.uiauto_dev(textMatches='无锁屏|No Lock Screen').right(resourceId='android:id/switch_widget')
            if not swicher.checked:
                swicher.click()
        except Exception, e:
            self.mdev.i('设置无锁屏出错！' + e.message)

    def set_24h_mode(self):
        try:
            self.wake_screen_up()
            self.go_setting('通用|General')
            time.sleep(1)
            dev = self.uiauto_dev
            dev(textMatches='日期和时间|Date & time').click()
            time.sleep(1)
            swicher = dev(textMatches='使用 24 小时制|Use 24-hour format').right(resourceId='android:id/switch_widget')
            if not swicher.checked:
                swicher.click()
        except Exception, e:
            self.mdev.i('设置24小时出错！' + e.message)

    def go_setting(self, module):
        try:
            dev = self.uiauto_dev
            dev.press.home()
            dev.press.home()
            dev.press.home()
            self.swipe_from_right()
            dev(textMatches="设置|Settings").click()
            time.sleep(1)
            if dev(text='同意|Agree').exists:
                dev(text='同意|Agree').click()
            time.sleep(1)
            m = dev(textMatches=module)
            while not m.exists:
                self.swipe_from_bottom(100)
            m.click()
        except Exception, e:
            self.mdev.i('定位到 设置-' + module + ' 出错！' + e.message)

    def open_browser(self):
        try:
            self.wake_screen_up()
            dev = self.uiauto_dev
            dev.press.home()
            dev.press.home()
            dev.press.home()
            dev(textMatches='浏览器|Browser').click()
            time.sleep(1)
            ok = dev(textMatches='同意|Agree|Accept')
            if ok.exists:
                ok.click()
        except Exception, e:
            self.mdev.i('设置浏览器出错！' + e.message)

    def swich_aosp(self):
        try:
            self.wake_screen_up()
            self.go_setting('通用|General')
            time.sleep(1)
            dev = self.uiauto_dev
            dev(textMatches='语言和输入法|Languages & input').click()
            time.sleep(1)
            dev(textMatches='虚拟键盘|Virtual keyboard').click()
            time.sleep(1)
            dev(textMatches='管理键盘|Manage keyboards').click()
            # 关闭第二想：搜狗输入法
            swicher_2 = dev(resourceId='android:id/switch_widget', instance=1)
            if swicher_2.checked:
                swicher_2.click()
            # 关闭第二想：搜狗输入法
            swicher_1 = dev(resourceId='android:id/switch_widget', instance=0)
            if not swicher_1.checked:
                swicher_1.click()
        except Exception, e:
            self.mdev.i('设置AOSP出错！' + e.message)

    def swich_eng(self):
        try:
            self.wake_screen_up()
            self.go_setting('通用|General')
            time.sleep(1)
            dev = self.uiauto_dev
            dev(textMatches='语言和输入法|Languages & input').click()
            time.sleep(1)
            dev(textMatches='语言|Languages').click()
            time.sleep(1)
            dev(textMatches='English').click()
        except Exception, e:
            self.mdev.i('设置Eng出错！' + e.message)

    def swipe_from_left(self, step=30):
        start_x = self.w * 0.1
        start_y = self.h * 0.5
        end_x = self.w * 0.9
        end_y = self.h * 0.5
        self.uiauto_dev.swipe(start_x, start_y, end_x, end_y, step)

    def swipe_from_right(self, step=30):
        end_x = self.w * 0.1
        end_y = self.h * 0.5
        start_x = self.w * 0.9
        start_y = self.h * 0.5
        self.uiauto_dev.swipe(start_x, start_y, end_x, end_y, step)

    def swipe_from_top(self, step=30):
        start_x = self.w * 0.5
        start_y = self.h * 0.2
        end_x = self.w * 0.5
        end_y = self.h * 0.8
        self.uiauto_dev.swipe(start_x, start_y, end_x, end_y, step)

    def swipe_from_bottom(self, step=30):
        start_x = self.w * 0.5
        start_y = self.h * 0.8
        end_x = self.w * 0.5
        end_y = self.h * 0.2
        self.uiauto_dev.swipe(start_x, start_y, end_x, end_y, step)

    def for_cts_prepare(self):
        try:
            self.mdev.i('设置不灭屏')
            self.screen_always_on()
            self.exit()
            self.mdev.i('链接wifi')
            self.connect_wifi('Meitu.cs.hw', 'mt13333331')
            self.exit()
            self.mdev.i('打开蓝牙')
            self.open_bluetooth()
            self.exit()
            self.mdev.i('打开GPS')
            self.open_gps()
            self.exit()
            self.mdev.i('设置无锁屏')
            self.non_screen_lock()
            self.exit()
            self.mdev.i('打开浏览器，去除引导界面')
            self.open_browser()
            self.exit()
            self.mdev.i('切换输入法为aosp')
            self.swich_aosp()
            self.exit()
            self.mdev.i('切换为24h制')
            self.exit()
            self.mdev.i('切换语言为Eng')
            self.swich_eng()
            self.exit()
        except Exception, e:
            self.mdev.i('出错' + e.message)

    def for_gts_prepare(self):
        LogUtil.i('gts prepare')
        pass

    def recovery_all(self):
        self.mdev.i('恢复出厂设置')
        try:
            self.wake_screen_up()
            self.go_setting('通用|General')
            time.sleep(1)
            dev = self.uiauto_dev
            self.swipe_from_bottom(20)
            dev(textMatches='清除数据|Erase data').click()
            time.sleep(1)
            dev(textMatches='恢复出厂设置|Reset the phone').click()
            time.sleep(1)
            dev(textMatches='格式化手机存储|Formatting cell phone storage').click()
            time.sleep(1)
            dev(textMatches='开始恢复|Start to reset').click()
            time.sleep(1)
            dev(textMatches='确定|OK').click()
        except Exception, e:
            self.mdev.i('恢复出厂设置出错！' + e.message)

    def wake_screen_up(self):
        d = self.uiauto_dev
        if d.screen == "off":
            self.mdev.i('出现灭屏，唤醒！')
            d.press(26)
        if d(textMatches='.*星期.*').exists or d(textMatches='.*解锁.*').exists:
            self.swipe_from_bottom(30)
        time.sleep(1)


class ScriptJava:
    def __init__(self, mdev):
        assert isinstance(mdev, MyDevice)
        # windows下的准备
        scirpt_apps = App.get_script_app()
        mdev.reinstall_apk(scirpt_apps[0])
        mdev.reinstall_apk(scirpt_apps[1])
        self.__mdev = mdev
        self.__head = mdev.adb_head + ' am instrument -w -r -e debug false -e class '
        self.__cts_gts_func = ' com.meitutest.autoscript.T9.T9Test#ctsOrGts'
        self.__recovery_func = ' com.meitutest.autoscript.T9.T9Test#recoveryAll'
        self.__fluency_func = ' com.meitutest.autoscript.T9.T9Test#fluencyTest'
        self.__runnner = ' com.meitutest.autoscript.test/android.support.test.runner.AndroidJUnitRunner'
        self.add_white_list()

    def add_white_list(self):
        LogUtil.i('修改系统白名单')
        d = self.__mdev
        head = d.adb_head.replace('shell', '')
        os.system(head + ' root')
        os.system(head + ' remount')
        os.system(head + ' push system_restrict_config.json /system/meitu/')

    def for_cts_prepare(self):
        self.__mdev.i('部署cts/gts')
        cmd = self.__head + self.__cts_gts_func + self.__runnner
        os.system(cmd)

    def for_gts_prepare(self):
        self.__mdev.i('部署cts/gts')
        cmd = self.__head + self.__cts_gts_func + self.__runnner
        os.system(cmd)

    def recovery_all(self):
        self.__mdev.i('恢复出厂设置')
        cmd = self.__head + self.__recovery_func + self.__runnner
        os.system(cmd)

    def for_fluency_test(self):
        self.__mdev.i('流畅性测试')
        cmd = self.__head + self.__fluency_func + self.__runnner
        LogUtil.w(cmd)
        os.system(cmd)


class GTS:
    def __init__(self, android_GTS_path, GTS_time, report_path, dev_no):
        self.roundNum = GTS_time
        dev = MyDevice(dev_num=dev_no)
        self.dev = dev
        self.DEV_rom_version = dev.get_rom()
        self.DEV_name = dev.get_name()
        self.GTS_root = android_GTS_path
        self.GTS_resultsDir = self.GTS_root + '/results/'
        self.GTS_logsDir = self.GTS_root + '/logs/'
        self.report_path = report_path
        self.report_info = "gts_" + self.DEV_name + "_" + self.DEV_rom_version
        self.report_full = self.report_path + "/" + self.report_info + '/'
        self.DEV_Serial = dev_no

    def show_gts_info(self):
        self.dev.i('----------------本次运行相关信息--------------')
        self.dev.i('设备名：' + self.DEV_name)
        self.dev.i('rom：' + self.DEV_rom_version)
        self.dev.i('序列号：' + str(self.DEV_Serial))
        self.dev.i('android-GTS路径：' + self.GTS_root)
        self.dev.i('logs路径：' + self.GTS_logsDir)
        self.dev.i('result路径：' + self.GTS_resultsDir)
        self.dev.i('-----------------------------------------\n')

    def get_commands(self):
        self.dev.i('\n----------------用到的命令---------------------')
        if self.roundNum == 0:
            self.dev.i('run gts --plan GTS')
        else:
            run_plan = 'run gts --retry ' + str(self.roundNum - 1)
        self.dev.i(run_plan)
        self.dev.i('----------------------------------------------------------')


class CTS:
    def __init__(self, android_cts_path, cts_media_path, report_path, dev_list):
        self.roundNum = 0
        self.dev_list = dev_list
        self.dev = MyDevice(dev_list[0])
        self.DEV_rom_version = self.dev.get_rom()
        self.DEV_name = self.dev.get_name()
        self.CTS_root = android_cts_path
        self.MEDIA_path = cts_media_path
        self.CTS_apk = self.CTS_root + '/testcases/CtsDeviceAdmin.apk'
        self.CTS_resultsDir = self.CTS_root + '/results/'
        self.CTS_logsDir = self.CTS_root + '/logs/'
        self.report_path = report_path
        self.report_info = self.DEV_name + "_" + self.DEV_rom_version
        self.report_full = self.report_path + "/" + self.report_info + '/'
        self.CTS_tradefed = self.CTS_root + "/tools/cts-tradefed"

    def show_cts_info(self):
        self.dev.i(content='--------------------------------本次运行相关信息---------------------------------')
        self.dev.i(content='设备名：' + self.DEV_name)
        self.dev.i(content='rom：' + self.DEV_rom_version)
        self.dev.i(content='设备号：' + str(self.dev_list))
        self.dev.i(content='android-cts路径：' + self.CTS_root)
        self.dev.i(content='----------------------------------------------------------------------------------\n')

    def get_commands(self):
        skip_optin = ' --disable-reboot --skip-preconditions '
        shards_option = ' --shard ' + str(len(self.dev_list))
        serial_option = ' '
        for num in self.dev_list:
            serial_option = serial_option + ' -s ' + num
        if self.roundNum == 0:
            run_plan = self.CTS_tradefed + ' run cts ' + skip_optin + shards_option + serial_option
        else:
            run_plan = self.CTS_tradefed + ' run cts --retry ' + str(
                self.roundNum - 1) + skip_optin + shards_option + serial_option
        return run_plan

    def run_cts(self, command):
        self.dev.i(content='执行命令：' + command)
        ps = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
        while True:
            if ps.poll() is not None:
                self.dev.i(content='---------------------------运行cts完毕！')
                break
            data = ps.stdout.readline()
            self.dev.i(content=str(data))

    def add_plan(self, command):
        self.dev.i(content='添加计划命令：' + command)
        ps = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
        while True:
            if ps.poll() is not None:
                self.dev.i('---------------------------添加plan完毕！')
                break
            data = ps.stdout.readline()
            self.dev.i("----" + str(data))

    def show_result(self):
        command = self.CTS_tradefed + ' l r '
        self.dev.i(content='显示运行结果：' + command)
        ps = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
        while True:
            if ps.poll() is not None:
                self.dev.i(content='---------------------------显示结果完毕！')
                break
            data = ps.stdout.readline()
            self.dev.i(content="----" + str(data))


class MyDevice:
    def __init__(self, dev_num):
        self.dev_num = dev_num
        if dev_num is None:
            self.adb_head = 'adb shell '
        else:
            self.adb_head = 'adb -s ' + self.dev_num + ' shell '
        self.log = './log/' + self.get_info() + '.txt'
        if not os.path.exists('./log/'):
            os.mkdir('./log/')
        self.info = self.get_info()

    # 获取手机型号
    def get_name(self):
        line = None
        command = self.adb_head + 'getprop ro.product.device'  # 可以直接在命令行中执行的命令
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        for line in info:  # 按行遍历
            line = line.strip('\r\n')
            # print line
        return str(line)

    def get_info(self):
        name = self.get_name()
        if self.dev_num is None:
            info = name
        else:
            rom = self.get_rom()
            info = name + '_' + rom
        return info

    # 获取rom版本
    def get_rom(self):
        line = None
        command = self.adb_head + 'getprop ro.custom.build.version'  # 可以直接在命令行中执行的命令
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        for line in info:  # 按行遍历
            line = line.strip()
        if line == '':
            version = ''
        else:
            version = re.findall(r"\d+\.?\d*", line)[0]
        return str(version)

    def check_installed(self, pkg):
        command = self.adb_head + ' pm list packages '
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        for line in info:
            if pkg in line:
                return True
        return False

    def i(self, content):
        log_time = TimeUtils.format_current_time_ms()
        content = self.info + "_" + self.dev_num + "\t\t\t\t" + str(content)
        LogUtil.i(content)
        f = open(self.log, "a")
        f.write(content + "\n")
        f.close()

    def get_pid(self, pkg):
        cmd = self.adb_head + ' ps | grep ' + pkg
        r = os.popen(cmd)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if info.__len__() < 1 or info is None:
            return None
        line = info.__getitem__(0)
        import re
        match_obj = re.match(r'[a-z,0-9,_]*\s*(\d*)', line, re.S | re.I)
        if not match_obj:
            return None
        return match_obj.group(1)

    def kill_app(self, pkg):
        import subprocess
        subprocess.Popen(self.adb_head + ' am force-stop ' + pkg, shell=True)

    def uninstall_apk(self, pkg):
        cmd = self.adb_head.replace('shell', '') + ' uninstall ' + pkg
        os.popen(cmd)
        self.i('卸载' + pkg + '完毕')

    def install_apk(self, app):
        assert isinstance(app, App)
        install = self.check_installed(app.pkg)
        self.i('检查' + app.pkg + '是否安装 ' + str(install))
        if not install:
            cmd = self.adb_head.replace('shell', '') + ' install  -r ' + app.apk_path
            os.system(cmd)
            self.i('安装' + app.apk_path + '完毕')
            time.sleep(5)

    def reinstall_apk(self, app):
        assert isinstance(app, App)
        cmd = self.adb_head.replace('shell', '') + ' install  -r ' + app.apk_path
        os.system(cmd)
        self.i('安装' + app.apk_path + '完毕')
        time.sleep(5)

    def push_apk(self, apk_path):
        cmd = self.adb_head.replace('shell', '') + ' push ' + apk_path + ' /sdcard/'
        os.popen(cmd)
        self.i('push' + apk_path + '完毕')

    def is_alive(self, pkg):
        command = self.adb_head + 'ps | grep ' + pkg
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if info.__len__() > 0:
            return True
        return False

    def is_media_exist(self):
        dev_num = self.dev_num
        if dev_num is None:
            command = 'adb shell ls /sdcard | grep test'
        else:
            command = 'adb -s ' + dev_num + ' shell ls /sdcard | grep test'  # 可以直接在命令行中执行的命令
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if len(info) > 0:
            return True
        else:
            return False

    def copy_media(self, media_path):
        if self.is_media_exist():
            self.i(content='media已存在，无需拷贝')
        else:
            self.i(content='正在拷贝文件... ...')
            if self.dev_num is None:
                cmd1 = 'adb push ' + media_path + ' /sdcard/test/'
            else:
                cmd1 = 'adb -s ' + self.dev_num + ' push ' + media_path + ' /sdcard/test/'
            ps = subprocess.Popen(cmd1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
            while True:
                if ps.poll() is not None:
                    self.i('---------------------------拷贝完毕！')
                    break
                data = ps.stdout.readline()
                self.i(content="----" + str(data))

    def cts_prepare(self, cts):
        assert isinstance(cts, CTS)
        self.copy_media(cts.MEDIA_path)
        script = ScriptJava(self)
        script.for_cts_prepare()

    def gts_prepare(self, gts):
        assert isinstance(gts, GTS)
        script = ScriptPy(self)
        script.for_gts_prepare()

    def wait_device_ready(self):
        while not self.is_boot_completed() or not self.is_connected():
            time.sleep(1)
            self.i('等待设备...')
            LogUtil.i('Wating for device ' + self.dev_num + '...')
        LogUtil.i(self.dev_num + ' Device ready!')
        self.i('设备连接成功！')

    def is_connected(self):
        cmd = 'adb devices '
        r = os.popen(cmd)
        lines = r.readlines()
        if lines is None or lines.__len__() < 1:
            return False
        else:
            for l in lines:
                if self.dev_num in l:
                    return True
        return False

    def is_boot_completed(self):
        cmd = self.adb_head + ' getprop sys.boot_completed'
        r = os.popen(cmd)
        lines = r.readlines()
        if lines is None or lines.__len__() < 1:
            return False
        else:
            for l in lines:
                if '1' in l:
                    return True
        return False

    def launch_by_cmd(self, app):
        self.install_apk(app)
        self.i('正在启动应用' + app.pkg)
        cmd = self.adb_head + ' am start -W -n ' + app.act
        r = os.popen(cmd)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if info.__len__() < 1 or info is None:
            return None
        for line in info:
            if 'TotalTime:' in line:
                time = int(line.replace('TotalTime:', '').strip())
                return time
        return -1

    def get_current_pkg(self):
        command = self.adb_head + 'dumpsys window  '  # 可以直接在命令行中执行的命令
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if info.__len__() < 1:
            return None
        for line in info:
            my_match = re.match(r'.*mFocusedWindow=Window\{.* (.*)\/(.*)\}', line, re.S | re.I)
            if my_match:
                return my_match.group(1)
            else:
                continue
        return None

    def get_focus_pkg_act(self):
        command = self.adb_head + 'dumpsys activity  '  # 可以直接在命令行中执行的命令
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if info.__len__() < 1:
            return None
        for line in info:
            my_match = re.match(r'.*realActivity=(.*)\/(.*)', line, re.S | re.I)
            if my_match:
                pkg = my_match.group(1)
                act = my_match.group(2)
                return pkg, act
            else:
                continue
        return None, None

    def catch_systrace(self):
        self.i('抓systrace')
        # cmd = self.adb_head + " input keyevent 120"
        cmd = self.adb_head + ' am broadcast -a meitu.intent.action.COLLECT_SYSTRACELOG_CAPTURE --el screenshot_time ' + str(
            int(time.time()))
        print cmd
        os.system(cmd)

    def cut_systrace(self, des_dir):
        self.i('剪切systrace文件至' + des_dir)
        trace_dir = '/sdcard/mtlog/mt/systrace/capture'
        cmd0 = self.adb_head + ' ls ' + trace_dir
        r = os.popen(cmd0)
        info = r.readlines()
        if info.__len__() < 1:
            self.i('未发现trace文件')
            return
        if not os.path.exists(des_dir):
            os.makedirs(des_dir)
        cmd1 = self.adb_head.replace('shell', '') + ' pull ' + trace_dir + ' ' + des_dir
        os.system(cmd1)
        cmd2 = self.adb_head + ' rm -rf ' + trace_dir
        os.system(cmd2)

    def copy_mtlog(self, des_dir, trace_only=True, cut=False):
        self.i('拷贝log至' + des_dir)
        if trace_only:
            src_dir = '/sdcard/mtlog/mt/systrace'
        else:
            src_dir = '/sdcard/mtlog'
        cmd = self.adb_head.replace('shell', '') + ' pull ' + src_dir + ' ' + des_dir
        os.system(cmd)
        if cut:
            self.i('清空' + src_dir)
            os.system(self.adb_head + ' rm -rf ' + src_dir + '/*')


'''
用于生成报告
'''


class BugUtils:
    S1 = u"S1-致命"
    S2 = u"S2-严重"
    S3 = u"S3-普通"
    S4 = u"S4-低等"
    S5 = u"S5-可忽略"

    Freq_a = "Always"
    Freq_s = "Sometimes"
    Freq_r = "Rarely"
    Freq_o = "OnlyOne"

    Is_new = "new(NA)"
    Old = "old"
    Non = u"未对比"
    __LOG_SERVER = r'\\172.16.1.230\Logs'

    '''
               # 方法作用:向bugzilla提交bug
               # 方法参数:product  产品
               #         component 子产品
               #         bug_severity 严重程度
               #         version 版本
               #         cf_freq 出现概率
               #	  cf_isold 是否老问题
               #	  cf_hw_version 硬件版本号
               #	  cf_model 模块路径
               #	  summary 摘要
               #	  comment 描述
               #         cf_imei  手机的IMEI
           '''

    @classmethod
    def postBug(cls, product, component, bug_severity, version, cf_freq, cf_isold, cf_hw_version, cf_model, summary,
                comment, imei, debug=True):
        if debug:
            product = '自动化专用'
            component = '自动化专用'
        data = {'username': 'cxq@meitu.com',
                'password': '123456',
                'product': product,
                'component': component,
                'bug_severity': bug_severity,
                'version': version,
                'cf_freq': cf_freq,
                'cf_isold': cf_isold,
                'cf_hw_version': cf_hw_version,
                'cf_model': cf_model,
                'summary': summary,
                'comment': comment,
                'cf_imei': imei}
        r = requests.post('http://172.16.19.240:81/postFilterBug.php', data=data)
        r.encoding = 'utf-8'
        id = 'None'
        title = None
        if r.ok:
            id_str = r.text
            title = r.text
            id = id_str[:id_str.index('-')]
            id = re.findall(r"\d+", id).__getitem__(0)
        # 打印提交成功的BUGID
        return id, title

    @classmethod
    def zipfolder(cls, foldername, filename):
        from os.path import join
        print foldername
        empty_dirs = []
        zip = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
        for root, dirs, files in os.walk(foldername):
            print root, dirs, files
            # 筛选空目录
            empty_dirs.extend(dir for dir in dirs if os.listdir(join(root, dir)) == [])
            for file in files:
                zip.write(join(root, file).decode("gbk"))
        for dir in empty_dirs:
            zip = zipfile.ZipFile(join(root, dir).decode("gbk" + "/"))
            zip.writestr(zip)
        zip.close()

    @classmethod
    def uploadFile(cls, srcfile, dstfile):
        if not os.path.isfile(srcfile):
            LogUtil.e(srcfile + u'不存在！')
        else:
            fpath, fname = os.path.split(dstfile)  # 分离文件名和路径
            if not os.path.exists(fpath):
                os.makedirs(fpath)  # 创建路径
            shutil.copy(srcfile, dstfile)  # 复制文件

    @classmethod  # 根据版本和机型获取Log服务器地址
    def get_log_server_dir(cls, dev_info):
        dir = BugUtils.__LOG_SERVER + '\\' + dev_info.replace('_', '_log\\r')
        if not os.path.exists(dir):
            os.makedirs(dir)
        return dir

    @classmethod
    def upload_bug_log(cls, dev_info, zip_file):
        server_dir = BugUtils.get_log_server_dir(dev_info)
        # server_dir = r'G:\1'
        LogUtil.i(u'将' + zip_file + u'上传至' + server_dir)
        BugUtils.uploadFile(zip_file, server_dir)


class MyReport:
    @classmethod
    def mkdir(cls, path):
        path = path.strip()
        path = path.rstrip('\\')
        isExists = os.path.exists(path)
        if not isExists:
            LogUtil.i(path)
            os.makedirs(path)
            return True
        LogUtil.i(None)
        return False

    @classmethod
    def zip_dir(cls, dirname, zipfilename):
        filelist = []
        if os.path.isfile(dirname):
            filelist.append(dirname)
        else:
            for (root, dirs, files) in os.walk(dirname):
                for name in files:
                    filelist.append(os.path.join(root, name))

        zf = zipfile.ZipFile(zipfilename, 'w', zipfile.zlib.DEFLATED)
        for tar in filelist:
            arcname = tar[len(dirname):]
            zf.write(tar, arcname)

        zf.close()

    @classmethod
    def get_cts_report(cls, cts):
        assert isinstance(cts, CTS)
        if os.path.exists(cts.report_full):
            backupDir = cts.report_path + '_backUp/' + cts.report_info + '_' + str(
                time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time())))
            LogUtil.i('拷贝旧的报告至' + backupDir)
            shutil.copytree(cts.report_full, backupDir)
            shutil.rmtree(cts.report_full)
        LogUtil.i('报告目录' + cts.report_full)
        MyReport.mkdir(cts.report_full)
        shutil.copytree(cts.CTS_resultsDir, cts.report_full + 'results')
        shutil.copytree(cts.CTS_logsDir, cts.report_full + 'logs')
        MyReport.zip_dir(cts.report_full, cts.report_path + "/" + cts.report_info + '.zip')

    @classmethod
    def get_gts_report(cls, gts):
        assert isinstance(gts, GTS)
        if os.path.exists(gts.report_full):
            backupDir = gts.report_path + '_backUp/' + gts.report_info + '_' + str(
                time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time())))
            LogUtil.i('拷贝旧的报告至' + backupDir)
            shutil.copytree(gts.report_full, backupDir)
            shutil.rmtree(gts.report_full)
        LogUtil.i('报告目录' + gts.report_full)
        MyReport.mkdir(gts.report_full)
        shutil.copytree(gts.GTS_resultsDir, gts.report_full + 'results')
        shutil.copytree(gts.GTS_logsDir, gts.report_full + 'logs')
        MyReport.zip_dir(gts.report_full, gts.report_path + "/" + gts.report_info + '.zip')


class TimeUtils:
    @classmethod
    def format_current_time_ms(cls):
        import datetime
        x = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
        return x

    @classmethod
    def format_current_to_file_name(cls):
        import datetime
        x = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
        return x


class DeviceHelper:
    def __init__(self, dev_num=None):
        self.dev_num = dev_num
        if dev_num is None:
            self.adb_head = 'adb shell '
        else:
            self.adb_head = 'adb -s ' + self.dev_num + ' shell '

    def wait_device_ready(self):
        while not self.is_boot_completed() or not self.is_connected():
            time.sleep(1)
            LogUtil.i('Wating for device ' + self.dev_num + ' ...')
        LogUtil.i(self.dev_num + ' Device ready!')

    def is_connected(self):
        cmd = 'adb devices '
        r = os.popen(cmd)
        lines = r.readlines()
        if lines is None or lines.__len__() < 1:
            return False
        else:
            for l in lines:
                if self.dev_num in l:
                    return True
        return False

    def is_boot_completed(self):
        cmd = self.adb_head + ' getprop sys.boot_completed'
        r = os.popen(cmd)
        lines = r.readlines()
        if lines is None or lines.__len__() < 1:
            return False
        else:
            for l in lines:
                if '1' in l:
                    return True
        return False

    def get_current_pkg(self):
        command = self.adb_head + 'dumpsys window  '  # 可以直接在命令行中执行的命令
        r = os.popen(command)  # 执行该命令
        info = r.readlines()  # 读取命令行的输出到一个list
        if info.__len__() < 1:
            return None
        for line in info:
            my_match = re.match(r'.*mFocusedWindow=Window\{.* (.*)\/(.*)\}', line, re.S | re.I)
            if my_match:
                return my_match.group(1)
            else:
                continue
        return None


class LogUtil:

    @classmethod
    def e(cls, s):
        print "\033[1;32;41m %s\t\t\t\t%s \033[0m" % (TimeUtils.format_current_time_ms(), s)

    @classmethod
    def i(cls, s):
        print "\033[1;36;0m %s\t\t\t\t%s \033[0m" % (TimeUtils.format_current_time_ms(), s)

    @classmethod
    def w(cls, s):
        print "\033[1;33;0m %s\t\t\t\t%s \033[0m" % (TimeUtils.format_current_time_ms(), s)


class EmailUtil:

    @classmethod
    def send_attache_file(cls, sender, pwd, reciever, subject, content, file_name=None):
        import smtplib
        import os.path
        import mimetypes
        import email.MIMEImage  # import MIMEImage
        server = smtplib.SMTP_SSL('smtp.qq.com', 465)
        server.login(sender, pwd)  # 仅smtp服务器需要验证时
        # 构造MIMEMultipart对象做为根容器
        main_msg = email.MIMEMultipart.MIMEMultipart()
        # 构造MIMEText对象做为邮件显示内容并附加到根容器
        text_msg = email.MIMEText.MIMEText(content)
        main_msg.attach(text_msg)

        ## 设置附件头
        if file_name is not None:
            # 构造MIMEBase对象做为文件附件内容并附加到根容器
            ctype, encoding = mimetypes.guess_type(file_name)
            if ctype is None or encoding is not None:
                ctype = 'application/octet-stream'
            maintype, subtype = ctype.split('/', 1)
            file_msg = email.MIMEImage.MIMEImage(open(file_name, 'rb').read(), subtype)
            basename = os.path.basename(file_name)
            file_msg.add_header('Content-Disposition', 'attachment', filename=basename)  # 修改邮件头
            main_msg.attach(file_msg)

        # 设置根容器属性
        main_msg['From'] = sender
        main_msg['To'] = ", ".join(reciever)
        main_msg['Subject'] = subject
        main_msg['Date'] = email.Utils.formatdate()

        # 得到格式化后的完整文本
        fullText = main_msg.as_string()

        # 用smtp发送邮件
        try:
            server.sendmail(sender, reciever, fullText)
        finally:
            server.quit()

    @classmethod
    def send_html(cls, reciever, subject, html_content):
        import smtplib
        sender = 'cxq@meitu.com'
        pwd = 'bZa2ZUTXddRjUKYZ'
        server = smtplib.SMTP_SSL('smtp.meitu.com', 465)
        server.login(sender, pwd)  # 仅smtp服务器需要验证时
        from email.mime.text import MIMEText
        message = MIMEText(html_content, 'html', 'utf-8')
        from email.header import Header
        message['From'] = sender
        message['To'] = ", ".join(reciever)
        message['Subject'] = Header(subject, 'utf-8')
        try:
            server.sendmail(sender, reciever, message.as_string())
        finally:
            server.quit()


class DrawUtil:
    @classmethod
    def draw_online(cls, data_list, file_name):
        import plotly
        import plotly.tools as py_tools
        import plotly.graph_objs as go
        py_tools.set_credentials_file(username='CrystalChen', api_key='UzaDnrbAUJ2dolVN7mXq')
        py_tools.set_config_file(world_readable=True, sharing='public')

        layout = go.Layout(title=file_name)
        fig = go.Figure(data=data_list, layout=layout)

        url = plotly.plotly.plot(fig, filename=file_name)
        LogUtil.i(file_name + '\t\t\t\t' + url)
        id = url[url.rindex('/') + 1:].strip()
        div_msg = '''
        <div>
        <a href="https://plot.ly/~CrystalChen/plot_id/?share_key=EOdkVkT4LaR5d46tpxHzlw" target="_blank" title="per_rate" style="display: block; text-align: center;">
        <img src="https://plot.ly/~CrystalChen/plot_id.png?share_key=EOdkVkT4LaR5d46tpxHzlw" alt="per_rate" style="max-width: 100%;width: 600px;"  width="600" onerror="this.onerror=null;this.src='https://plot.ly/404.png';" />
        </a>
        <script data-plotly="CrystalChen:plot_id" sharekey-plotly="EOdkVkT4LaR5d46tpxHzlw" src="https://plot.ly/embed.js" async></script>
        </div>
        '''
        div_msg = div_msg.replace('plot_id', str(id))
        return div_msg

    @classmethod
    def draw_and_get_id(cls, data_list, file_name):
        import plotly
        import plotly.tools as py_tools
        import plotly.graph_objs as go
        py_tools.set_credentials_file(username='CrystalChen', api_key='UzaDnrbAUJ2dolVN7mXq')
        py_tools.set_config_file(world_readable=True, sharing='public')

        layout = go.Layout(title=file_name)
        fig = go.Figure(data=data_list, layout=layout)

        url = plotly.plotly.plot(fig, filename=file_name)
        LogUtil.i(file_name + '\t\t\t\t' + url)
        id = url[url.rindex('/') + 1:].strip()
        return id


if __name__ == '__main__':
    dev_num = 'c4b5c29f'
    dev = MyDevice(dev_num)
    dev.wait_boot_complete()
    # script = DevScript(dev)
    # script.recovery_all()
